package com.symagic.gesture;

import java.util.ArrayList;

import android.app.Activity;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GesturePoint;
import android.gesture.GestureStroke;
import android.gesture.Prediction;
import android.os.SystemClock;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.symagic.R;

public class SymagicGestureLogic {
	

	//flag the gesture drawing
	private boolean drawingGesture;

	private GestureLibrary library = null;

	// the score's Threshold
	private double scoreThreshold;

	// gesture to build
	private ArrayList<GesturePoint> gesturePoints = null;

	// build the render
	private ShapeRenderer render = null;

	// the gesture performed listener
	SymagicGesturePerformedListener listener = null;

	private boolean beingGesturing;

	public SymagicGestureLogic(Activity father) {

		// Load the gesture library
		library = GestureLibraries.fromRawResource(father, R.raw.gestures);
		if (!((GestureLibrary) library).load()) {
			father.finish();
		}

		// init the render
		render = new ShapeRenderer();

		// init the being gesturing state
		beingGesturing = false;

		// init the score threshold
		scoreThreshold = 1.0;
		
		//init the drawing flag
		drawingGesture = false;

	}

	// when user is drawing the gesture, we just push the pointer data to the
	// buffer.
	public void onTouchDragged(float x, float y, float pointer) {

		// check the flag and force the single touch
		if (!beingGesturing || pointer != 0)
			return;

		// Gesture point add.
		gesturePoints.add(new GesturePoint(x, y, SystemClock.uptimeMillis()));
		drawingGesture = true;

	}

	// when user's finger touch the screen, we know he is going to draw a
	// gesture, so we build a buffer to hold the data
	public void onTouchDown(float x, float y, float pointer, int button) {

		// force the single touch
		if (pointer != 0)
			return;

		gesturePoints = new ArrayList<GesturePoint>();
		beingGesturing = true;
	}

	// the thrashold setter
	public void setSocreThrashold(double thrashlod) {
		scoreThreshold = thrashlod;
	}

	// Performing the gesture recognize when user's finger leave the screen
	public void onTouchUp(float x, float y, float pointer, int button) {

		// check the flag
		if (!beingGesturing || gesturePoints.size() == 0 || pointer != 0)
			return;

		Gesture gesture = new Gesture();
		gesture.addStroke(new GestureStroke(gesturePoints));
		ArrayList<Prediction> predictions = library.recognize(gesture);
		
		drawingGesture = false;

		// record the highest scores
		if (predictions.size() > 0) {
			double score = Double.MIN_VALUE;
			Prediction predictionWithHighestScore = null;
			for (int i = 0; i < predictions.size(); i++) {
				if (score < predictions.get(i).score) {
					score = predictions.get(i).score;
					predictionWithHighestScore = predictions.get(i);
				}

			}

			// the drawn gesture is similar(score >= 1) to one of the gesture
			// library in gesture database.
			if (score >= scoreThreshold) {
				// call the listener if we got one
				if (listener != null) {
					listener.onGesturePerformed(predictionWithHighestScore,
							gesturePoints);
				}
			}

			gesturePoints = null;

		}

		beingGesturing = false;

	}

	public ArrayList<GesturePoint> getCurrentGesturePoints() {
		return gesturePoints;
	}

	// the callback setter
	public void setListener(SymagicGesturePerformedListener listener) {
		this.listener = listener;
	}

	public void drawGesture(SpriteBatch batch) {

		if (gesturePoints != null && gesturePoints.size() > 0) {

			// Set the projection and the transform matrix
			// the projection and transform matrix is the same as the batch
			render.setProjectionMatrix(batch.getProjectionMatrix());
			render.setTransformMatrix(batch.getTransformMatrix());

			render.begin(ShapeRenderer.ShapeType.Line);

			// Rending the line

			GesturePoint lastPoint = gesturePoints.get(0);
			for (int i = 1; i < gesturePoints.size(); i++) {
				render.line(lastPoint.x,
						Gdx.graphics.getHeight() - lastPoint.y,
						gesturePoints.get(i).x, Gdx.graphics.getHeight()
								- gesturePoints.get(i).y);
				lastPoint = gesturePoints.get(i);
			}

			render.end();

		}
	}
	
	public boolean getGestureDrawingState(){
		return drawingGesture;
	}

}
